package com.jasongj.kafka.consumer;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import java.io.*;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class WriteDownload {
    private static final Logger logger = LogManager.getLogger(WriteDownload.class);
    static List<String> signatures = new ArrayList<String>();
    static String baseDirLedger = "/var/www/html/p2p/";
    // static String baseDirLedger = "e:/log_dir/p2p/download_7z/";
    static String baseDirKeyword = "/var/www/html/url_keyword/";
    static String topic = "";
    static String baseDownLoadDir ="";
    static String baseDir = "/home/ubuntu/writeBlock/";
    // static String baseDir =  "e:/log_dir/";

    public static void main(String[] args) throws Exception {
        if (args == null || args.length != 1) {
            System.err.println(
                    "请输入正确topic名字 !\n\tjava -jar 7z.jar  ${topic_name} ");
            System.exit(1);
        }
        topic = args[0];
        //topic = "p2p";
        if(topic.equals("p2p")){
            baseDownLoadDir = baseDirLedger;
            System.out.println("p2p:"+baseDownLoadDir);
        }
        if(topic.equals("url_keyword")){
            baseDownLoadDir = baseDirKeyword;
            System.out.println("url_keyword:"+baseDownLoadDir);
        }
        while(true) {
             writeTree();
             Thread.sleep(1*60*1000);
         }
    }

    public static void writeTree() throws Exception {
        Date now = new Date();
        long time = 1*60*1000;//1分钟
        Date beforeDate = new Date(now .getTime() - time);//1分钟前的时间

        SimpleDateFormat dateFormatDay= new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat dateFormatHour= new SimpleDateFormat("yyyy-MM-dd-HH");
        SimpleDateFormat dateFormatMinute= new SimpleDateFormat("yyyy-MM-dd-HH-mm");
        SimpleDateFormat dateFormatSecond = new SimpleDateFormat("mmss");

        String  day = dateFormatDay.format( beforeDate );
        String  hour = dateFormatHour.format( beforeDate );
        String  minute = dateFormatMinute.format( beforeDate );
        String  second = dateFormatSecond.format(now);

        File dataFile = new File(baseDir+topic+"/"+hour+"/"+minute);
        File hashFile = new File(baseDownLoadDir+"download/"+hour+"/"+minute+"-down-hash");

        File downLoadDir = new File(baseDownLoadDir+"download/"+hour);
        File downLoadFile = new File(baseDownLoadDir+"download/"+hour+"/"+minute+"-down");

        File treeDir  = new File(baseDir+topic+"/tree/"+day);
        File treeFile = new File(baseDir+topic+"/tree/"+day+"/"+hour);

        if (dataFile.exists()&&!hashFile.exists()) {
            if (!downLoadDir.isDirectory()) {
                downLoadDir.mkdirs();
            }
            if (!treeDir.isDirectory()) {
                treeDir.mkdirs();
            }
            if (!treeFile.exists()) {
                treeFile.createNewFile();
            }
            //1、设置现在时间延时1分钟，copy延时1分钟的文件到下载目录,这里操作浪费磁盘空间,还耗时 ,暂时注释
            /*copyFile(dataFile,downLoadFile);*/
            //2、获取copy文件sha-512值，将该值写校验文件
            String hashCode = getFileSHA512(dataFile);
            logger.info(dataFile.getName() +" hash code is:"+hashCode);
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(hashFile)));
            out.write(hashCode);
            out.close();
            //3、打包copy文件和校验文件
            ZipFile zipFile = new ZipFile(baseDownLoadDir+"download/"+hour+"/"+minute+"-down.zip");
            ArrayList filesToAdd = new ArrayList();
            filesToAdd.add(dataFile);
            filesToAdd.add(new File(baseDownLoadDir+"download/"+hour+"/"+minute+"-down-hash"));
            try {
                ZipParameters parameters = new ZipParameters();
                parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // set compression method to deflate compression
                parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
                zipFile.addFiles(filesToAdd, parameters);
            } catch (ZipException e) {
                e.printStackTrace();
            }
            //4、将2中的校验值生成merkle树，以小时为单位
            signatures.add(hashCode);
            System.out.println("signatures.size() is:"+signatures.size());
            if(signatures.size()!=1){
                MerkleTree leaf = new MerkleTree(signatures);
                byte[] serializedTree = leaf.serialize();
                writeFileByBytes(baseDir+topic+"/tree/"+day+"/"+hour,serializedTree,false);
            }
           // File zipFileReadOnly = new File(baseDir+"\\download\\"+hour+"\\"+minute+"-down.zip");
            //5、设定下载文件为只读
           // zipFileReadOnly.setReadOnly();
            //bittorrent 种子文件调用命令
            //executeNewFlow("btmakemetafile "+baseDownLoadDir+"/download/"+hour+"/"+minute+"-down.zip"+" http://120.53.240.110:6969/announce");
            //7z 压缩命令 压缩 文件
            executeCommand("7z a -t7z "+baseDownLoadDir+"download/"+hour+"/"+minute+".7z "+baseDownLoadDir+"download/"+hour+"/"+minute+"-down.zip");
        }
        //每小时清空一次merkle节点
        if("0000".equals(second)){
            if(signatures.size()!=1){
                signatures.clear();
            }
        }
    }

    public static String getFileSHA512(File file) {
        String str = "";
        try {
            str = getHash(file, "SHA-512");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    public static String getHash(File file, String hashType) throws Exception {
        InputStream fis = new FileInputStream(file);
        byte buffer[] = new byte[1024];
        MessageDigest md5 = MessageDigest.getInstance(hashType);
        for (int numRead = 0; (numRead = fis.read(buffer)) > 0; ) {
            md5.update(buffer, 0, numRead);
        }
        fis.close();
        return toHexString(md5.digest());
    }

    public static String toHexString(byte b[]) {
        StringBuilder sb = new StringBuilder();
        for (byte aB : b) {
            sb.append(Integer.toHexString(aB & 0xFF));
        }
        return sb.toString();
    }

    public static void writeFileByBytes(String fileName, byte[] bytes, boolean append) throws IOException {
        try(OutputStream out = new BufferedOutputStream(new FileOutputStream(fileName, append))){
            out.write(bytes);
        }
    }

    public static int executeCommand(String cmds) {
        logger.info("命令："+cmds);
        int iden = 0;
        try {
            //下面是linux命令，window命令只需要把下面 String[] command = {"/bin/sh","-c",cmds}的"/bin/sh"变成"cmd"。
            String[] command = {"/bin/sh","-c",cmds};
            //String[] command = {"cmd","-c",cmds};
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            processBuilder.redirectErrorStream(true);//通过子进程所产生的任何错误输出随后由该对象的start()方法启动将与标准输出合并
            Process process = null;
            BufferedReader bufferedReader = null;
            try {
                process = processBuilder.start();
                bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line = null;
                while ((line = bufferedReader.readLine()) != null) {
                    logger.info(line);
                }
                int active = process.waitFor();
                if(active==0) {//命令执行成功，如gradle打包success而不是failed。
                    iden = 1;
                    System.out.println(" the command is ："+cmds +" excute success!");
                }
            } catch(Exception ex){
                ex.printStackTrace();
            }finally {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (process != null) {
                    process.destroy();
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return iden;
    }

}